/**************************************************************************************************
*******
**************************************************************************************************/


/**************************************************************************************************
    Filename:       jump_table.c
    Revised:
    Revision:

    Description:    Jump table that holds function pointers and veriables used in ROM code.


**************************************************************************************************/

/*******************************************************************************
    INCLUDES
*/
#include "comdef.h"
#include "jump_function.h"
#include "global_config.h"
#include "OSAL_Tasks.h"
#include "rf_phy_driver.h"
#include "pwrmgr.h"
#include "gpio.h"
#include "timer.h"
#include "uart.h"
#include "log.h"


#define DEF_HARD_FAULT_LOG_DEBUG                (1)

//#define DEF_HARD_FAULT_FS_ENABLE 1


/*******************************************************************************
    MACROS
*/


/*
    HF FS Recorder Description
    HF_NUM_FSID: [0xFE00], save the total number of hard fault records
    HF_REC_FSID: [0xFE01 -- 0xFE00+MAX_FS_HARD_FAULT_REC_NUM]
            only save the latest HF_REC,when HF_SUM_FSID > MAX_FS_HARD_FAULT_REC_NUM
            , the earliset recorder will be replaced
    HF_REC Total Size:
    MAX_FS_HARD_FAULT_REC_NUM *(FSID_HARD_FAULT_SIZE + 1+ FS_Header*2)

*/


#if( DEF_HARD_FAULT_FS_ENABLE)
    #include "fs.h"
#endif

#define DEF_HARD_FAULT_DUMP_SP_LEN          256
#define MAX_FS_HARD_FAULT_REC_NUM           16  // should be 2**n

#define FSID_HARD_FAULT_BASE                0xFE00
#define FSID_HARD_FAULT_NUM                 (FSID_HARD_FAULT_BASE)

#define FSID_HARD_FAULT_CURRENT(x)          (FSID_HARD_FAULT_BASE+1+((x)&(MAX_FS_HARD_FAULT_REC_NUM-1) ) )

#define FSID_REC_EXTRA_BUF_LEN              4  // for hf rec , 2 for osal event 1 for osal sys tick, 1 for rtc tick 

#define FSID_HARD_FAULT_SIZE                ((17+1+FSID_REC_EXTRA_BUF_LEN)*4+DEF_HARD_FAULT_DUMP_SP_LEN)
/*
    17 for cpu reg,
    1 for ICSR,
*/

#if(DEF_HARD_FAULT_LOG_DEBUG)

    #define HF_DBG_LOG_PINOUT                   P9
    #define HF_DBG_LOG                          log_printf
    #define HF_DBG_LOG_baudrate                 115200
    #define HF_DBG_DUMMY_IO                     P27
    #define HF_DBG_LOG_INIT                     {rom_uart_init(HF_DBG_LOG_baudrate,HF_DBG_LOG_PINOUT,HF_DBG_DUMMY_IO,NULL);}

#else

    #define HF_DBG_LOG(...)
    #define HF_DBG_LOG_INIT

#endif


void (*trap_c_callback)(void);
extern void log_printf(const char* format, ...);
extern uint32_t rtc_get_counter(void);
extern uint32 osal_sys_tick;
extern int rom_uart_init(int baud, gpio_pin_e tx_pin, gpio_pin_e rx_pin, comm_cb_t cb);


#ifdef DEF_HARD_FAULT_FS_ENABLE

uint8 _hard_fault_fs_write( uint16_t id, uint16_t len, uint8_t* pBuf)
{
    AP_WDT_FEED;
    int ret = PPlus_SUCCESS;
    uint32_t free_size = 0;
    hal_fs_get_free_size(&free_size);

    if( free_size < len+32)
    {
        if(hal_fs_get_garbage_size(NULL) > len+32)
        {
            uint32_t t0 = rtc_get_counter();
            hal_fs_garbage_collect();
            HF_DBG_LOG("DO HF_FS Garbage Collect Cost %d (rtcTick) \n",rtc_get_counter()-t0);
        }
        else
        {
            HF_DBG_LOG("hf_wr fail\n");
            return NV_OPER_FAILED;
        }
    }

    ret = hal_fs_item_write(id,  pBuf,len);

    if(ret !=0)
    {
        HF_DBG_LOG("hf_wr_ret:%d\n",ret);
        return NV_OPER_FAILED;
    }

    //LOG("Success\n");
    return SUCCESS;
}

void _hard_fault_record_process(uint32_t* stk,uint32_t* buf,uint16_t len)
{
    uint32_t rec[FSID_HARD_FAULT_SIZE/4];
    int i;
    fs_set_psr_protection(0);

    for(i=0; i<len; i++)
        rec[i]=buf[i];

    for(i=0; i<17; i++)
        rec[len+i]=stk[i];

    rec[len+17]=(*(volatile uint32_t*)0xE000ED04);
    uint32 sp = stk[0]&0x1ffffffc;

    for(i=0; i<DEF_HARD_FAULT_DUMP_SP_LEN; i=i+4)
    {
        if(sp+i>0x1ffffffc)
            break;

        rec[len+18+i/4]=read_reg(sp+i);
    }

    uint8_t rec_num;
    uint16_t rec_id;
    int ret=hal_fs_item_read(FSID_HARD_FAULT_NUM,&rec_num,1,NULL);

    if(ret==PPlus_ERR_FS_NOT_FIND_ID)
    {
        rec_num=0;
        rec_id=FSID_HARD_FAULT_CURRENT(rec_num);
    }
    else if(ret==PPlus_SUCCESS)
    {
        rec_num=rec_num+1;
        rec_id=FSID_HARD_FAULT_CURRENT(rec_num);
    }
    else
    {
        HF_DBG_LOG("\n[HF REC]fs err:%d\n",ret);
        return;
    }

    HF_DBG_LOG("\n[HF REC]save:num %d id %04x\n",rec_num,rec_id);
    _hard_fault_fs_write(FSID_HARD_FAULT_NUM,1,&rec_num);
    _hard_fault_fs_write(rec_id,FSID_HARD_FAULT_SIZE,(uint8_t*)rec);
}
void _hard_fault_record_load(void)
{
    uint8_t rec_num;
    uint32_t rec[FSID_HARD_FAULT_SIZE/4];
    int i,j;
    #if(DEBUG_INFO==0)
    /*
        use rom log when debug info turn off
        otherwise, use system log_printf
    */
    HF_DBG_LOG_INIT;
    #endif
    int ret=hal_fs_item_read(FSID_HARD_FAULT_NUM,&rec_num,1,NULL);

    if(ret==PPlus_SUCCESS)
    {
        log_printf("\n[HF REC] Found recorder Total Num %d\n",rec_num+1);
    }
    else
    {
        log_printf("\n[HF REC] No recorder Found\n");
        return;
    }

    for(i=0; i<MAX_FS_HARD_FAULT_REC_NUM; i++)
    {
        AP_WDT_FEED;
        ret=hal_fs_item_read(FSID_HARD_FAULT_CURRENT(i),(uint8_t*)rec,FSID_HARD_FAULT_SIZE,NULL);

        if(ret==SUCCESS)
        {
            HF_DBG_LOG("\n[HF REC] Load ID = [%04x]================\n",FSID_HARD_FAULT_CURRENT(i));
            uint32_t* stk = &rec[FSID_REC_EXTRA_BUF_LEN];
            HF_DBG_LOG("R0-R3        = 0x%08x 0x%08x 0x%08x 0x%08x\n", stk[9], stk[10], stk[11], stk[12]);
            HF_DBG_LOG("R4-R7        = 0x%08x 0x%08x 0x%08x 0x%08x\n", stk[1], stk[2], stk[3], stk[4]);
            HF_DBG_LOG("R8-R11       = 0x%08x 0x%08x 0x%08x 0x%08x\n", stk[5], stk[6], stk[7], stk[8]);
            HF_DBG_LOG("R12,SP,LR,PC = 0x%08x 0x%08x 0x%08x 0x%08x\n", stk[13], stk[0], stk[14], stk[15]);
            HF_DBG_LOG("PSR  = 0x%08x  ", stk[16]);
            HF_DBG_LOG("ICSR = 0x%08x\n", stk[17]);
            HF_DBG_LOG("[OSAL]idx %d Func 0x%08x systick %08x rtc %08x\n ",rec[0],rec[1],rec[2],rec[3]);
            HF_DBG_LOG("-----------dump stack--------------\n");

            for(j=0; j<DEF_HARD_FAULT_DUMP_SP_LEN; j=j+4)
            {
                if(stk[0]+j>0x1ffffffc)
                    break;

                if(0==(j&0x0f))
                    HF_DBG_LOG("\n[%08X]",stk[0]+j);

                HF_DBG_LOG("%08x ",stk[18+j/4]);
            }

            HF_DBG_LOG("\n");
        }
        else
            break;
    }
}

#endif



void _hard_fault(uint32_t* arg)
{
    uint32_t* stk = (uint32_t*)((uint32_t)arg);
    uint8 task_cnt = *(uint8*)JUMP_FUNCTION(TASK_COUNT);
    pTaskEventHandlerFn pFunc=NULL;
    uint8_t* p_activeTaskID = (uint8_t*)0x1fff08b4;//activeTaskID
    uint32_t buf[FSID_REC_EXTRA_BUF_LEN];
    HF_DBG_LOG_INIT;
    HF_DBG_LOG("\n[Hard fault handler]\n");
    HF_DBG_LOG("R0-R3        = 0x%08x 0x%08x 0x%08x 0x%08x\n", stk[9], stk[10], stk[11], stk[12]);
    HF_DBG_LOG("R4-R7        = 0x%08x 0x%08x 0x%08x 0x%08x\n", stk[1], stk[2], stk[3], stk[4]);
    HF_DBG_LOG("R8-R11       = 0x%08x 0x%08x 0x%08x 0x%08x\n", stk[5], stk[6], stk[7], stk[8]);
    HF_DBG_LOG("R12,SP,LR,PC = 0x%08x 0x%08x 0x%08x 0x%08x\n", stk[13], stk[0], stk[14], stk[15]);
    HF_DBG_LOG("PSR  = 0x%08x  ", stk[16]);
    HF_DBG_LOG("ICSR = 0x%08x\n", *(volatile uint32_t*)0xE000ED04);

    if(p_activeTaskID[0]<task_cnt)
        pFunc = ((pTaskEventHandlerFn*)(JUMP_FUNCTION(TASKS_ARRAY)))[p_activeTaskID[0]];

    buf[0]=p_activeTaskID[0];
    buf[1]=(uint32_t)pFunc;
    buf[2]=osal_sys_tick;
    buf[3]=rtc_get_counter();
    HF_DBG_LOG("[OSAL]idx %d Func 0x%08x systick %08x rtc %08x\n ",buf[0],buf[1],buf[2],buf[3]);
    (void) buf;
    HF_DBG_LOG("-----------dump stack--------------\n");
    uint32 sp = stk[0]&0x1ffffffc;

    for(int i=0; i<DEF_HARD_FAULT_DUMP_SP_LEN; i=i+4)
    {
        if(sp+i>0x1ffffffc)
            break;

        if(0==(i&0x0f))
            HF_DBG_LOG("\n[%08X]",sp+i);

        HF_DBG_LOG("%08x ",read_reg(sp+i));
    }

    #if( DEF_HARD_FAULT_FS_ENABLE)
    _hard_fault_record_process(stk,buf,FSID_REC_EXTRA_BUF_LEN);
    #endif

    if (trap_c_callback)
    {
        trap_c_callback();
    }

    while (1);
}
#if   defined ( __CC_ARM )
// *INDENT-OFF*
__asm void hard_fault(void)
{
    PRESERVE8
    IMPORT  _hard_fault
    ldr     r0, = 0x1FFF0800 /*store in global config 0x1fff0400 0x1fff0800*/
    subs    r0, r0, #72
    mov     r1, sp
    str     r1, [r0]
    adds    r0, #4
    stmia   r0!, {r4 - r7}
    mov     r4, r8
    mov     r5, r9
    mov     r6, r10
    mov     r7, r11
    stmia   r0!, {r4 - r7}
    pop     {r4 - r5} /* pop rom Hardfault stack*/
    pop     {r4 - r7} /* pop exception entry R0-R1*/
    stmia   r0!, {r4 - r7}
    pop     {r4 - r7}/* pop exception entry R12 LR PC xPSR*/
    stmia   r0!, {r4 - r7}
    subs    r0, r0, #68
    ldr     r1, = _hard_fault
    ldr     r2, = 0x1FFF1830 /*mov sp to rom initial_sp*/
    mov     sp, r2
    bx      r1
    ALIGN   4
}

#elif defined ( __GNUC__ )
__attribute__((naked)) void hard_fault(void)
{
    asm("ldr     r0, = 0x1FFF0800\n\r"
        "sub    r0, r0, #72\n\r"
        "mov     r1, sp\n\r"
        "str     r1, [r0]\n\r"
        "add    r0, #4\n\r"
        "stmia   r0!, {r4 - r7}\n\r"
        "mov     r4, r8\n\r"
        "mov     r5, r9\n\r"
        "mov     r6, r10\n\r"
        "mov     r7, r11\n\r"
        "stmia   r0!, {r4 - r7}\n\r"
        "pop     {r4 - r5}\n\r"
        "pop     {r4 - r7}\n\r"
        "stmia   r0!, {r4 - r7}\n\r"
        "pop     {r4 - r7}\n\r"
        "stmia   r0!, {r4 - r7}\n\r"
        "sub    r0, r0, #68\n\r"
        "ldr     r1, = _hard_fault\n\r"
        "ldr     r2, = 0x1FFF1830\n\r"
        "mov     sp, r2\n\r"
        "bx      r1\n\r");
}


#endif
// *INDENT-ON*

/*******************************************************************************
    CONSTANTS
*/
// jump table, this table save the function entry which will be called by ROM code
// item 1 - 4 for OSAL task entry
// item 224 - 255 for ISR(Interrupt Service Routine) entry
// others are reserved by ROM code
const uint32_t* const jump_table_base[256] __attribute__((section("jump_table_mem_area"))) =
{
    (const uint32_t*)0,                         // 0. write Log
    (const uint32_t*)osalInitTasks,             // 1. init entry of app
    (const uint32_t*)tasksArr,                  // 2. task list
    (const uint32_t*)& tasksCnt,                // 3. task count
    (const uint32_t*)& tasksEvents,             // 4. task events
    0, 0, 0, 0, 0,                              // 5 - 9, reserved for rom patch
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,               // 10 - 19, reserved for rom patch
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,               // 20 - 29, reserved for rom patch
    0, 0, 0, 0, 0, 0, 0, 0,                     // <30 - - 37>
    0, 0,
    0, 0, 0, 0, 0, 0, //40 - 45
    0, 0, 0, 0,                                 //46 - 49
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,               // 50 - 59, reserved for rom patch
    0,   // < 60 -
    0,
    0,
    0,
    0, 0, 0, 0, 0, 0,                           //  -69>, reserved for rom patch
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,               // 70 -79, reserved for rom patch
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,               // 80 - 89, reserved for rom patch
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,               // 90 - 99, reserved for rom patch
    (const uint32_t*)hal_pwrmgr_sleep_process,         // <100 -
    (const uint32_t*)hal_pwrmgr_wakeup_process,
    (const uint32_t*)rf_phy_ini,
    0,
    0,
    0,
    0, 0, 0, 0,                       // - 109, reserved for rom patch
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     // 110 -119, reserved for rom patch
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     // 120 -129, reserved for rom patch
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     // 130 -139, reserved for rom patch
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     // 140 -149, reserved for rom patch
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     // 150 -159, reserved for rom patch
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     // 160 -169, reserved for rom patch
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     // 170 -179, reserved for rom patch
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     // 180 -189, reserved for rom patch
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     // 190 -199, reserved for rom patch
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     // 200 - 209, reserved for rom patch
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     // 210 - 219, reserved for rom patch
    (const uint32_t*)hard_fault, 0, 0, 0, 0, 0, 0, 0,           // 220 - 227
    0, 0,       // 228 - 229
    0, 0, 0, 0, 0,  // 230 - 234
    (const uint32_t*)hal_UART0_IRQHandler,      // 235 uart irq handler
    0, 0, 0, 0, 0,    // 236 - 240
    0, 0, 0, 0, 0, 0, 0, 0, 0,     // 241 - 249, for ISR entry
    0, 0, 0, 0, 0, 0                  // 250 - 255, for ISR entry
};



/*******************************************************************************
    Prototypes
*/


/*******************************************************************************
    LOCAL VARIABLES
*/


/*********************************************************************
    EXTERNAL VARIABLES
*/
uint32 global_config[SOFT_PARAMETER_NUM] __attribute__((section("global_config_area")));




